﻿
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.VFX;

public class VFXManager : MonoBehaviour
{
    static protected VFXManager mInstance;

    static public VFXManager Instance
    {
        get
        {
            if (mInstance == null)
            {
                mInstance = new VFXManager();
            }
            return mInstance;
        }
    }

    static readonly int positionID = Shader.PropertyToID("position");
    static readonly int targetPositionID = Shader.PropertyToID("targetPosition");
    static readonly int directionID = Shader.PropertyToID("direction");

    GameObject m_rootGameObject;
    Dictionary<VisualEffectAsset, VFXEffectTypeData> mEffectTypeData = new Dictionary<VisualEffectAsset, VFXEffectTypeData>(32);

    public void Start()
    {
        m_rootGameObject = new GameObject("VFXSystem");
        m_rootGameObject.transform.position = Vector3.zero;
        m_rootGameObject.transform.rotation = Quaternion.identity;
        GameObject.DontDestroyOnLoad(m_rootGameObject);
        Application.lowMemory += OnLowMemory;
    }

    public void SpawnPointEffect(VisualEffectAsset asset, Vector3 position, Vector3 normal)
    {
        VFXEffectTypeData effectData;
        if (!mEffectTypeData.TryGetValue(asset, out effectData))
        {
            effectData = RegisterImpactType(asset);
        }
        effectData.EventAttribute.SetVector3(positionID, position);
        effectData.EventAttribute.SetVector3(directionID, normal);
        effectData.Effect.Play(effectData.EventAttribute);
        effectData.Effect.pause = false;
        //effectData.LastTriggerTime = TimeManager.Instance.CurrentSystemMilliseconds;
        effectData.Active = true;
    }

    public void SpawnLineEffect(VisualEffectAsset asset, Vector3 start, Vector3 end)
    {
        VFXEffectTypeData effectType;
        if (!mEffectTypeData.TryGetValue(asset, out effectType))
            effectType = RegisterImpactType(asset);

        effectType.EventAttribute.SetVector3(positionID, start);
        effectType.EventAttribute.SetVector3(targetPositionID, end);
        effectType.Effect.Play(effectType.EventAttribute);
        effectType.Effect.pause = false;
        //effectType.LastTriggerTime = TimeManager.Instance.CurrentSystemMilliseconds;
        effectType.Active = true;
    }

    public void ClearCache()
    {
        DeleteChildren(m_rootGameObject.transform);
        mEffectTypeData.Clear();
    }

    public void DeleteChildren(Transform transform, bool includeSelf = false)
    {
        for (int i = transform.childCount - 1; i >= 0; i--)
        {
            GameObject.Destroy(transform.GetChild(i).gameObject);
        }
        if (includeSelf)
        {
            GameObject.Destroy(transform.gameObject);
        }
    }

    VFXEffectTypeData RegisterImpactType(VisualEffectAsset template)
    {
        if (template == null)
            throw new System.Exception("VFX Template 为null");
        if (mEffectTypeData.ContainsKey(template))
            throw new System.Exception("mEffectTypeData Contains template");

        GameObject go = new GameObject(template.name);
        //go.transform.parent = m_rootGameObject.transform;
        go.transform.position = Vector3.zero;
        go.transform.rotation = Quaternion.identity;
        go.transform.localScale = Vector3.one;
        var vfx = go.AddComponent<VisualEffect>();
        vfx.visualEffectAsset = template;
        vfx.Reinit();
        vfx.Stop();

        var data = new VFXEffectTypeData
        {
            Effect = vfx,
            EventAttribute = vfx.CreateVFXEventAttribute(),
        };

        mEffectTypeData.Add(template, data);

        return data;
    }

    private void OnLowMemory()
    {
        //ClearCache();
    }
}
